﻿#region using

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

#endregion

namespace JupiterLibrary
{
    /// <summary>
    /// Define una camara controlada por el usuario (FirstPersonCamera)
    /// </summary>
    public class Camera:Node
    {
        public delegate void KinetUpdateMethod();

        static SoundEffect sonidoPasos;
        public static SoundEffectInstance sonidoPasosInstance;

        public KinetUpdateMethod KinectUpdate;
        public Vector3 RelativeKinectRotation=Vector3.Zero;
        /// <summary>
        /// Sensibilidad al mover el ratón
        /// </summary>
        public float Sensitivity = 1;

        /// <summary>
        /// Displacement in seconds
        /// </summary>
        public float Speed = 1;

        public float NearPlane = 0.1f;

        public float FarPlane = 1000f;

        public float FOV = MathHelper.PiOver4;

        public Scene Scene;

        public bool Collide = false;

        /// <summary>
        /// Projection matrix
        /// </summary>
        public Matrix Projection;

        public Vector3 SpawPosition { get; set; }
        /// <summary>
        /// View matrix
        /// </summary>
        public Matrix View;

        public bool UseKinect;

        public Vector3 KinectOffset;
        public Vector3 lastNewOffset;

        public Camera(Node parentNode)
            : base(parentNode)
        {
            sonidoPasos = Jupiter.Content.Load<SoundEffect>("music/Pasos");

            sonidoPasosInstance = sonidoPasos.CreateInstance();

        }

        protected override void UpdateLocal()
        {

            // Nos aseguramos que la rotación es en grados
            RotationInDegrees = true;
            Vector3 lastPosition = Position;
            Vector3 lastPosition2 = Position;

            CalculateTranslation();

            if (UseKinect)
            {
                KinectUpdate();
            }
            else
                CalculateMouseRotation(-Jupiter.Input.MouseRelativeX, -Jupiter.Input.MouseRelativeY);

            if (Collide && lastPosition != Position)
            {
                Vector3 fpos = Scene.Collision.GetPosition(lastPosition, Position - lastPosition);

                if (Scene.Collision.HayColision)
                {
                    Position = fpos;
                }
            }

            // Veamos i podemos mover la cabeza
            Vector3 newOffset = Vector3.Transform(KinectOffset, Quaternion.CreateFromYawPitchRoll(MathHelper.ToRadians(this.RotationAngles.Y), MathHelper.ToRadians(this.RotationAngles.X), MathHelper.ToRadians(this.RotationAngles.Z)));

            {
                lastPosition = Position;
                Position += (newOffset-lastNewOffset);

                lastNewOffset = newOffset;

                Vector3 fpos = Scene.Collision.GetPosition(lastPosition, Position - lastPosition,0);

                Position = fpos;
            }

            base.UpdateLocal();

            /*
            //cOMO TRANSFORMAR BIEN???
            Vector3 newOffset = Vector3.Transform(KinectOffset * 15, Quaternion.CreateFromYawPitchRoll(MathHelper.ToRadians( this.RotationAngles.Y), MathHelper.ToRadians(this.RotationAngles.X), MathHelper.ToRadians(this.RotationAngles.Z)));
            
            base.Local *= Matrix.CreateTranslation( newOffset);
            //base.Local *= Matrix.CreateTranslation(KinectOffset * 15);
            */
        }

        public void CreateViewAndProjectionMatrix()
        {
            Projection = Matrix.CreatePerspectiveFieldOfView(FOV, Jupiter.Video.GraphicsDevice.Viewport.AspectRatio, NearPlane, FarPlane);

            View = Matrix.Invert(World);
        }
        void CalculateTranslation()
        {
            float speed=Jupiter.At1Second(Speed);

            if (Jupiter.Input.IsKeyPressed(Keys.W)) this.Position += World.Forward * speed;
            if (Jupiter.Input.IsKeyPressed(Keys.S)) this.Position += World.Backward * speed;

            if (Jupiter.Input.IsKeyPressed(Keys.A)) this.Position += World.Left * speed;
            if (Jupiter.Input.IsKeyPressed(Keys.D)) this.Position += World.Right * speed;

            if (Jupiter.Input.IsLeftMouseButtonPressed()) this.Position += World.Up * speed;
            if (Jupiter.Input.IsRightMouseButtonPressed()) this.Position += World.Down * speed;

        }

        void CalculateMouseRotation(int relativeX, int relativeY)
        {
            float mouseX = relativeX * Sensitivity;
            float mouseY = relativeY * Sensitivity;

            float pitch = RotationAngles.X + (mouseY * 0.01f);
            float yaw = RotationAngles.Y + (mouseX * 0.01f);

            // Límites del pitch
            if (pitch > 90.0f)
                pitch = 90.0f;
            else if (pitch < -90.0f)
                pitch = -90.0f;

            // Límites del yaw
            if (yaw >= 360.0f)
                yaw = 0.0f;
            else if (yaw <= -360.0f)
                yaw = 0.0f;

            // Actualizamos los ángulos
            RotationAngles = new Vector3(pitch, yaw, 0.0f);
        }

    }
}
